#include "stdafx.h"
#include "BasicThreadSpecific.h"
#include "BasicDoublyLinkedList.h"
#include "BasicMutex.h"

namespace BasicSkinTimer
{
	template <typename T> class Locker {
	public:
		Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
		~Locker() { m_lockable.unlock(); }
	private:
		T& m_lockable;
	};

	typedef Locker<BasicMutex> MutexLocker;

	static BasicDoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
	{
		//static DoublyLinkedList<PlatformThreadSpecificKey>& staticList = *new DoublyLinkedList<PlatformThreadSpecificKey>();
		static BasicDoublyLinkedList<PlatformThreadSpecificKey> staticList;
		return staticList;
	}

	static BasicMutex& destructorsMutex()
	{
		//	static Mutex& staticMutex = *new Mutex();
		static BasicMutex staticMutex;
		return staticMutex;
	}

	class PlatformThreadSpecificKey : public BasicDoublyLinkedListNode<PlatformThreadSpecificKey> {
	public:
		friend class BasicDoublyLinkedListNode<PlatformThreadSpecificKey>;

		PlatformThreadSpecificKey(void (*destructor)(void *))
			: m_destructor(destructor)
		{
			m_tlsKey = TlsAlloc();
			//if (m_tlsKey == TLS_OUT_OF_INDEXES)
			//    CRASH();
		}

		~PlatformThreadSpecificKey()
		{
			TlsFree(m_tlsKey);
		}

		void setValue(void* data) { TlsSetValue(m_tlsKey, data); }
		void* value() { return TlsGetValue(m_tlsKey); }

		void callDestructor()
		{
			if (void* data = value())
				m_destructor(data);
		}

	private:
		void (*m_destructor)(void *);
		DWORD m_tlsKey;
		PlatformThreadSpecificKey* m_prev;
		PlatformThreadSpecificKey* m_next;
	};

	long& tlsKeyCount()
	{
		static long count;
		return count;
	}

	DWORD* tlsKeys()
	{
		static DWORD keys[kMaxTlsKeySize];
		return keys;
	}

	void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
	{
		*key = new PlatformThreadSpecificKey(destructor);

		MutexLocker locker(destructorsMutex());
		destructorsList().push(*key);
	}

	void threadSpecificKeyDelete(ThreadSpecificKey key)
	{
		MutexLocker locker(destructorsMutex());
		destructorsList().remove(key);
		delete key;
	}

	void threadSpecificSet(ThreadSpecificKey key, void* data)
	{
		key->setValue(data);
	}

	void* threadSpecificGet(ThreadSpecificKey key)
	{
		return key->value();
	}

	void ThreadSpecificThreadExit()
	{
		for (long i = 0; i < tlsKeyCount(); i++)
		{

			BasicThreadSpecific<int>::Data* data = static_cast<BasicThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
			if (data)
				data->destructor(data);
		}

		MutexLocker locker(destructorsMutex());
		PlatformThreadSpecificKey* key = destructorsList().head();
		while (key)
		{
			PlatformThreadSpecificKey* nextKey = key->next();
			key->callDestructor();
			key = nextKey;
		}
	}
}